package ultimaVersion;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;



/**
 * @uml.dependency   supplier="ControlDeMemoria"
 */
public class MemoriaDe8bits1Kb implements ControlDeMemoria{
	
	/**Archivo que reprecenta a la memoria fisica y se sincroniza
	 * con el ArrayList mem
	 * En el caso del cambio de memoria se debe crear otra clase que implemente ControlDeMemoria
	 * y el archivo se llamará memXXX.bin donde XXX es la capacidad
	 * */
	private String archNombre;
	private File arch;
	
	/**Constante que indica la cantidad máxima de celdas en una memoria de 1Kbite
	 * @uml.property  name="MAXCELDA"
	 */
	private static final int MAXCELDA = 128;
	
	/**
	 * Control del acceso a la memoria: 0 apagado, 1 lectura, -1 escritura
	 * @uml.property  name="lectoEscritura"
	 */
	private static int lectoEscritura;

	/**Indica cual es la celda habilitada
	 * @uml.property  name="celda"
	 */
	private int celda;
	
	/**Lista que facilita el acceso a los datos del archivo al estar sincronizados
	 * @uml.property  name="mem"
	 */
	private ArrayList<Boolean> mem;

	/**El constructor toma los datos del archivo mem1024.bin, que son los guardados en la sesion 
	 * anterior, y los coloca en el arraylist mem
	 * */
	public MemoriaDe8bits1Kb() {
		super();
		this.archNombre = new String("mem1024.bin");
		this.celda = 0;
		MemoriaDe8bits1Kb.lectoEscritura=0;
		this.mem = new ArrayList<Boolean>();
		String linea=this.accMemLect();
		this.alArreglo(linea);
	}

	
	/**Formatea los datos extraidos del archivo y los coloca
	 * en el arreglo mem
	 * */
	private final void alArreglo(String linea) {
		if(linea==null)return;
		StringTokenizer st = new StringTokenizer(linea, "-");
		while(st.hasMoreTokens()) {
			String parte = st.nextToken();
			mem.add(new Boolean(Boolean.valueOf(parte)));
			}
	 }

	/**Convierte el contenido del arreglo que reprecenta a la
	 * memoria del dispositivo en datos imprimobles. 
	 * Un "-" indica memoria vacia
	 * */
	public String toString() {
		String salida = new String();
		for(int i=0;i<mem.size();i++){
			salida=salida.concat(mem.get(i).toString());
			salida=salida.concat("-");
		}
		if(salida==null)return "-";
		return salida;
	}


	/**
	 * indica la posicion habilitada para la lectura o escritura
	 * @uml.property  name="celda"
	 */
	public int getCelda() {
		return celda;
	}

	/**
	 * habilita a la próxima posicion de memoria
	 * @uml.property  name="celda"
	 */
	public boolean setCelda(int celda) {
		if (celda > MAXCELDA)
			return false;
		this.celda = celda * 8;
		return true;
	}
	

	/**
	 * Entrega un arreglo correspondiente al dato de la celda actual
	 */
	public ArrayList<Boolean> getContenidoDeLaCelda() {
		if((MemoriaDe8bits1Kb.lectoEscritura==0)&&(MemoriaDe8bits1Kb.lectoEscritura==-1))return null;
		else {
			ArrayList<Boolean>l=new ArrayList<Boolean>();
			for(int i=0;i<8;i++){
				l.add(new Boolean(mem.get(celda+i)));
				}
			return l;
			}
	}
	
	/**
	 * Sobreescribe dato existente en la celda actual con el contenido de un buffer y sincroniza con el
	 * archivo
	 */
	public boolean setContenidoDeLaCelda(ArrayList<Boolean> buffer) {
		if((MemoriaDe8bits1Kb.lectoEscritura==0)||(MemoriaDe8bits1Kb.lectoEscritura==1))return false;
		else {
			for (int i = 0; i < 8; i++) {
				this.mem.set(celda + i, buffer.get(i));
			}
			return this.accMemEscr();
			}
	}
	

	/**agrega al final del arraylist mem, un arraylist buffer
	 */
	public boolean addBuffer(ArrayList<Boolean> buffer){
		if(buffer.isEmpty())return false;
		if((MemoriaDe8bits1Kb.lectoEscritura==0)||(MemoriaDe8bits1Kb.lectoEscritura==1))return false;
		if((celda<MAXCELDA)&&(buffer.size()==8)){
			celda++;
			Boolean me=mem.addAll(buffer);
			Boolean arch=this.accMemEscr();
			return (me&arch);
			}
		else return false;
	}

			
	/**borra el dato especifico por la celda actual
	 */
	public boolean inicializaActual(){
		for (int i=0;i<8;i++){
			mem.set(celda+i, false);
		}
		if(celda*8==mem.size())celda--;
		return accMemEscr();
	}
	
	/**Accede al archivo para igualarlo con la lista
	 * */
	private final boolean accMemEscr(){

		arch=new File(archNombre);
		BufferedWriter escritor;
		if (!(arch.exists())){
			try {
				arch.createNewFile();
				try {
			 		escritor = new BufferedWriter(new FileWriter(archNombre));
			 		escritor.write("-");
					escritor.close();
				} catch (IOException e) {
					return false;
				}
			} catch (IOException e) {
				return false;
			}
		}
		try {
	 		escritor = new BufferedWriter(new FileWriter(archNombre));
			escritor.write(this.toString());
			escritor.close();
		} catch (IOException e) {
			return false;
		}
		return true;
	}
	
	/**Accede al archivo para inicializar la lista
	 * */
	private final String accMemLect(){
		arch=new File(archNombre);
		String linea;
		if (!(arch.exists())){
				return null;
			}
		try {
	 		BufferedReader lector = new BufferedReader(new FileReader(archNombre));
	 		linea=new String(lector.readLine());
	 		lector.close();
		} catch (IOException e) {
			return null;
		}
		return linea;
	}
	
	/**Devuelve la cantidad de celdas usadas
	 * */
	public int celdasUsadas() {
		return Math.round(mem.size()/8);
	}
	
	/**Reinicia a la memoria
	 * */
	public void inicializa(){
		mem.removeAll(mem);
		arch=new File(archNombre);
		arch.delete();
	}


	/** 
	 * Control del acceso a la memoria: 0 apagado, 1 lectura, -1 escritura
	 */
	public int getLectoEscritura() {
		return lectoEscritura;
	}


	/** 
	 * Control del acceso a la memoria: 0 apagado, 1 lectura, -1 escritura
	 * */
	public void setLectoEscritura(int lectoEscritura) {
		MemoriaDe8bits1Kb.lectoEscritura = lectoEscritura;
	}


	public void cierraAcceso() {
		lectoEscritura=0;
	}
}
